import concurrent.futures
import datetime
import logging
import os
import sys
import traceback

from absl import app, flags
import pandas as pd

from coin.base.datetime_util import (convert_string_to_dates, iterate_date)
from coin.strategy.mm.tool.log_pta_dumper import (PtaStrategy)
from coin.experimental.xguo.order_and_feed_stats.logic.order_event_util \
  import get_order_event_dir
from coin.support.proto_log.logic.util import run_from_og_log_archive

FLAGS = flags.FLAGS


class OrderEventDumper(PtaStrategy):
  def __init__(self, market_type, exchange, trading_date, machine, owner):
    super().__init__(market_type, exchange, trading_date, machine)
    self._owner = owner

  def save_order_event(self, root_path):
    for symbol in self._rows.keys():
      self._stat_df[symbol] = pd.DataFrame(self._rows[symbol], columns=self._header)
      order_event_path = self._get_order_event_path(symbol, root_path)
      self._stat_df[symbol].to_csv(order_event_path)

  def _get_order_event_path(self, symbol, root_path):
    dir_name = get_order_event_dir(root_path,
                                   self._machine,
                                   self._trading_date,
                                   self._exchange,
                                   self._owner,
                                   self._market_type)
    if not os.path.isdir(dir_name):
      os.makedirs(dir_name, exist_ok=True)
    file_name = '%s/%s.csv' % (dir_name, symbol)
    return file_name


def launch(exchange, trading_date, root_dir, machine, market_type, owner, order_event_dir):
  start_time = datetime.datetime.combine(trading_date, datetime.datetime.min.time())
  # 24 will omit some logs..
  hours = 25
  strategy = OrderEventDumper(market_type, exchange, trading_date, machine, owner)
  run_from_og_log_archive(on_log_callback=strategy.on_log2,
                          market_type=market_type,
                          exchange=exchange,
                          start_time=start_time,
                          end_time=start_time + datetime.timedelta(hours=hours),
                          root_dir=root_dir,
                          machine=machine,
                          owner=owner)

  strategy.save_order_event(order_event_dir)
  return 0


def main(_):
  exchange = FLAGS.exchange
  market_type = FLAGS.market_type
  start_date = FLAGS.start_date
  end_date = FLAGS.end_date
  root_dir = os.path.expanduser(FLAGS.root_dir)
  machine = FLAGS.machine
  owner = FLAGS.owner
  order_event_dir = FLAGS.order_event_dir
  max_workers = FLAGS.max_workers
  assert market_type in ['Spot', 'Futures', 'Margin']
  assert start_date, '--start_date must be specified.'
  assert end_date, '--end_date must be specified.'
  assert machine, '--machine must be specified.'
  assert exchange, '--exchange must be specified.'
  assert owner, '--owner must be specified.'

  start_date = convert_string_to_dates(start_date)[0]
  end_date = convert_string_to_dates(end_date)[0]
  trading_dates = [td for td in iterate_date(start_date, end_date)]

  future_trading_date_list = []
  with concurrent.futures.ProcessPoolExecutor(max_workers=max_workers) as executor:
    for trading_date in trading_dates:
      print('Running for %s %s %s ...' % (trading_date, machine, exchange))
      sys.stdout.flush()
      future = executor.submit(launch,
                               exchange,
                               trading_date,
                               root_dir,
                               machine,
                               market_type,
                               owner,
                               order_event_dir)
      future_trading_date_list.append((future, trading_date))

  for future, trading_date in future_trading_date_list:
    try:
      future.result()
    except ValueError as e:
      print('Fail to dump order event.', machine, trading_date, exchange, owner, market_type)
      print(traceback.format_exc())


if __name__ == '__main__':
  flags.DEFINE_string('exchange', 'Okex', 'Exchange name.')

  flags.DEFINE_string('market_type', None, 'Spot, Futures, Margin')

  flags.DEFINE_string('start_date', None, 'yyyymmdd')

  flags.DEFINE_string('end_date', None, 'yyyymmdd. Feed at end_date is not checked.')

  flags.DEFINE_string('machine', 'strategy-04.aliyun-cn-hongkong', 'Instance machine name.')

  flags.DEFINE_string('owner', None, '')

  flags.DEFINE_string('root_dir', '~/data/og_proto_log', 'root_dir.')

  flags.DEFINE_string('order_event_dir', 'order_event', 'order_event_dir.')

  flags.DEFINE_integer('max_workers', 12, '')

  logging.basicConfig(level='DEBUG', format='%(levelname)8s %(asctime)s %(name)s] %(message)s')
  app.run(main)
